home *** CD-ROM | disk | FTP | other *** search
- #include <new.h>
- #include "bisearch.h"
-
- /* BISEARCH_
-
- The constructor puts the start node on s_open, the goal node on
- t_open and sets the number of operators to the specified value.
-
- */
-
- BISEARCH_::BISEARCH_(NODE_ *start, NODE_ *goal, int num)
- {
- s_open.addtohead(*start); // add start node to the head of s_open
- t_open.addtohead(*goal); // add goal node to the head of t_open
- num_op = num;
- }
-
-
-
- /* ~BISEARCH_
-
- We don't make the destructor pure virtual because we can't be sure
- a destructor will be defined in the derived class.
-
- */
-
- BISEARCH_::~BISEARCH_()
- {
- }
-
-
-
- /* GENERATE
-
- Start looking for a solution and print it if found.
-
- */
-
- #ifdef MSC
- extern int no_mem(size_t);
- #else
- extern void no_mem();
- #endif
-
- void BISEARCH_::generate()
- {
- NODE_
- *node,
- *s_node,
- *t_node;
-
- #ifdef MSC
- _set_new_handler(no_mem);
- #else
- set_new_handler(no_mem);
- #endif
-
- if (!(node = bisolve()))
- {
- puts("No solution found");
- return;
- }
-
- /* solve() stores the node that connects x_open with y_closed, i.e., the node
- that is on both of these lists, at the head of x_open and of y_closed. */
-
- s_node = (NODE_ *) s_open.gethead();
- t_node = (NODE_ *) t_open.gethead();
-
- /* now find out on which list the node is stored: s_open or t_open. */
-
- if (node->equal(*s_node))
- {
- /* first we print the first half of the path. Next we check if s_node
- matches the tail node of t_closed, that is the goal node. If it does,
- the search paths didn't connect and this means we already printed the
- entire solution path. If it doesn't we still need to print the second
- half of the solution path, starting with the parent of the first node
- on y_closed. */
-
- print_sol(s_node);
-
- if (!s_node->equal(*t_closed.gettail()))
- print_sol_2(((NODE_ *) t_closed.gethead())->getparent());
- // as we searched backward we need a different printing routine
- }
- else // apply the same procedure, but reversed
- {
- if (!t_node->equal(*s_closed.gettail()))
- print_sol(((NODE_ *) s_closed.gethead())->getparent());
-
- print_sol_2(t_node);
- }
- }
-
-
-
- /* PRINT_SOL
-
- Trace back the solution path through the parent *'s. Recursively
- prints that part of the solution path that reaches from the node
- that connects both search paths back to the start.
-
- */
-
- void BISEARCH_::print_sol(NODE_ *sol) const
- {
- if (!sol)
- return;
- print_sol(sol->getparent());
- sol->display();
- }
-
-
-
- /* PRINT_SOL_2
-
- Prints that part of the solution path that reaches from the node
- connecting both search paths to the goal node.
-
- */
-
- void BISEARCH_::print_sol_2(NODE_ *sol) const
- {
- while (sol)
- {
- sol->display();
- sol = sol->getparent();
- }
- }
-
-
-
- /* BISOLVE
-
- This routine determines if the search will be continued backward or
- forward. If s-open contains fewer nodes than t-open the search will
- proceed forward, otherwise backward. If both lists are empty the
- process ends with failure.
-
- */
-
- NODE_ *BISEARCH_::bisolve()
- {
- NODE_
- *node = NULL;
-
- while (node == NULL)
- {
- if(s_open.gethead() == NULL || t_open.gethead() == NULL)
- break; // no more nodes left in either list
-
- if (s_open.getcount() <= t_open.getcount())
- node = solve(&s_open, &s_closed, &t_closed); // search forward
- else
- node = solve(&t_open, &t_closed, &s_closed); // search backward
- }
- return(node);
- }
-
-
-
- /* SOLVE
-
- This routines implements the actual search engine. It takes the first
- node from xOPEN, if xOPEN is empty the search process fails. If not,
- the node is moved to xCLOSED. Next, the node's successors are generated
- by calling NODE_::expand(). Then, every successor is made to point
- back to its parent, so that the solution path may be traced back once
- the solution is found. Next, the routine checks for every successor if
- it is also on yClosed, i.e., if it is part of the other path of the
- search process. If so, this means that the particular node connects
- both paths and the search process halts. Each successor is passed to add()
- for further processing, if add() returns 0 this means that the
- successor already was on xOPEN and consequently it can be thrown away,
- i.e. it gets deallocated.
-
- Solve() return the node that connects both paths if found and NULL
- otherwise.
-
- */
-
- NODE_ *BISEARCH_::solve(SORTEDLIST_ *x_open, SORTEDLIST_ *x_closed, SORTEDLIST_ *y_closed)
- {
- NODE_
- *aux,
- *father,
- *child;
-
- father = (NODE_ *) x_open->gethead(); // get first node from open
- x_open->remove_head();
- x_closed->addtohead(*father); // move it to closed
-
- child = father->expand(num_op); // expand node
- while (child)
- {
- child->setparent(father); // sets up solution path
-
- if ((aux = (NODE_ *) y_closed->lookup(*child)) != NULL)
- { // here the paths connect
- x_open->addtohead(*child); // we store both of the nodes
- y_closed->remove_found(); // at the start of the lists
- y_closed->addtohead(*aux); // so we can easily find them back
- return(child); // return node connecting both paths
- }
-
- aux = child->getnext();
- if (!add(x_open, x_closed, child))
- delete(child);
- child = aux;
- }
- return(NULL);
- }
-